package com.hopscotch.config;
import com.hopscotch.interceptor.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 真正执行的是自己实现的UserDetailsServiceImpl类
    @Autowired
    private UserDetailsService userDetailsService;

    //认证异常处理器对象
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    //权限异常处理器对象
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;

    //认证过滤器对象
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    // 获取AuthenticationManager对象，该对象会在登录的业务层进行调用
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();

    }

    /**
     * 配置账户认证
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 使用UserDetailsService实现类进行认证
        // 暂时都是明文存明文取,没有任何加密
        /*auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder( ) {
            @Override
            public String encode(CharSequence rawPassword) {
                return rawPassword.toString();
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return encodedPassword.equals(rawPassword.toString());
            }
        });*/
        // 密码使用BCrypt加密算法存储
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 配置权限信息
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 允许匿名访问，登录后无法访问
                // 匿名访问,无论登录与否都可访问
                .antMatchers("/register","/img/**","/user/login","/").permitAll()
                // 其他所有资源,认证后(登录)访问
                .antMatchers("/**").authenticated( );
        //使用SpringSecurity自带的登录表单
        //.and( ).formLogin( );
        //禁用跨域，使用Security自带的login接口测试时需要加入，否测报错
        //http.csrf().disable();
        //跨域相关，前端未进行跨域配置时需要使用
        http.cors().and().csrf().disable();

        // 指定认证异常处理类
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
        // 指定权限异常处理类
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
        // 【重点】基于token，所以不需要session，即所以认证信息都存放在token中，不需要session
        http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        // 指定认证过滤器
        http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}
